/**
 * hxhtalarmxml.c
 */

#include <stdlib.h>
#include <string.h>

#include <Base.h>
#include <Net.h>
#include <XmlParser.h>

#include "hxhtalarmxml.h"

// COPY_BEGIN: copy from NetCommon.h and NetCommon.c
enum VSP_XML{
    VSP_SEND_XML = 110,
    VSP_RECV_XML,
    VSP_OTHER_XML
};

static mxml_node_t* ParserXML(char* buffer, int len, int flags)
{
    char* pbuf = buffer;
    if(flags == VSP_SEND_XML)
    {
	VSP_SNDHEADER hdr = *(VSP_SNDHEADER *)pbuf;
	pbuf += sizeof(hdr);
	return ParserDataXML(pbuf, hdr.xmlLen);
    }else if(flags == VSP_RECV_XML)
    {
        VSP_RECVHEADER hdr = *(VSP_RECVHEADER *)pbuf;
        pbuf += sizeof(hdr);
        return ParserDataXML(pbuf, hdr.xmlLen);
    }else if(flags == VSP_OTHER_XML)
    {
	return ParserDataXML(pbuf, len);
    }
    return NULL;	
}
// COPY_END

/**
 * get value from xml buffer
 * @param
 *		pXmlBuff		input	xml buffer
 *		buffSize		input	buffer size
 *		pNodeName	input	node name
 *		pAttrName	input	attribute name, can be NULL when no attribute
 * @return
 *		value string
 */
static inline char *getValueFromXmlBuff(char *pXmlBuff, int buffSize, char *pNodeName, char *pAttrName) {
	mxml_node_t *pRoot = ParserXML(pXmlBuff, buffSize, VSP_SEND_XML);
	mxml_node_t *pNode = HaveNode(pRoot, pNodeName);
	return pAttrName == NULL ? GetKeyValue(pNode, pNodeName) : GetKeyValue(pNode, pAttrName);
}

void hxhtSetAlarmOutputStatus(AlarmGPIO *pGpio, char *pXmlBuff, int buffSize) {
	char *pDeviceId = getValueFromXmlBuff(pXmlBuff, buffSize, "DeviceID", NULL);
	char *pOp = getValueFromXmlBuff(pXmlBuff, buffSize, "Op", NULL);
	if (pDeviceId != NULL && pOp != NULL) {
		pGpio->addr = (char) atoi(pDeviceId);
		pGpio->enable = (bool) atoi(pOp);
	}
}

int hxhtGetAlarmOutputStatus(char *pXmlBuff, int buffSize, AlarmGPIO *pGpio) {
	int needSize = snprintf(pXmlBuff, buffSize, "<Message>\n"
							"<DeviceID>%d</DeviceID>\n"
							"<Op>%d</Op>\n"
						"</Message>\n", pGpio->addr, pGpio->enable) + 1;	// add '\o'
	return needSize <= buffSize ? needSize : -1;
}

#define DAY_HOUR_NUM 24
#define PLAN_CH_NUM 168
#define PLAN_ON '1'
#define PLAN_OFF '0'
Scheme *hxhtSetAlarmSchemeList(char *pXmlBuff, int buffSize) {
	char *pPlan = getValueFromXmlBuff(pXmlBuff, buffSize, "Plan", NULL);
	if (pPlan != NULL) {
		Scheme *pHead = NULL;
		Scheme *pTail = NULL;
		Scheme *pScheme = NULL;
		char prevPlan = PLAN_OFF;
		char currPlan;
		int i;
		
		for (i = 0; i <= PLAN_CH_NUM; i++) {
			currPlan = (i == PLAN_CH_NUM ? PLAN_OFF : pPlan[i]);
			if (prevPlan != currPlan) {	// change
				char week = i / DAY_HOUR_NUM;
				char hour = i % DAY_HOUR_NUM;
			
				if (currPlan == PLAN_ON) {	// new scheme, start time
					pScheme = (Scheme *) calloc(1, sizeof(Scheme));
					pScheme->startTime.week = week;
					pScheme->startTime.hour = hour;
					if (pHead == NULL) {	// head, first
						pHead = pScheme;
					} else {	// add to tail
						pTail->pNext = pScheme;
					}
					pTail = pScheme;
				} else if (currPlan == PLAN_OFF) {	// end time
					pScheme->endTime.week = week;
					pScheme->endTime.hour = hour;
				} else {	// error
					LOGERROR("char %c in %d is error\n", currPlan, i);
					while (pHead != NULL) {
						pScheme = pHead->pNext;
						free(pHead);
						pHead = pScheme;
					}
					return NULL;
				}
			}		// END: if (prevPlan != currPlan)
			prevPlan = currPlan;
		}		// END: for (i = 0; i < PLAN_CH_NUM; i++)
		return pHead;
	} else {
		LOGERROR("get Plan value error\n");
		return NULL;
	}
}

int hxhtGetAlarmSchemeList(char *pXmlBuff, int buffSize, Scheme *pList) {
	int beforePlanNeedSize = snprintf(pXmlBuff, buffSize, "<Message>\n"
							"<Plan>");
	if (beforePlanNeedSize + PLAN_CH_NUM >= buffSize) {
		return -1;
	}
	
	char *pBeginPlan = pXmlBuff + beforePlanNeedSize;
	memset(pBeginPlan, 0, PLAN_CH_NUM);
	Scheme *pScheme = pList;
	while (pScheme != NULL) {
		int start = pScheme->startTime.week * DAY_HOUR_NUM + pScheme->startTime.hour;
		int end = pScheme->endTime.week * DAY_HOUR_NUM + pScheme->endTime.hour;
		int i;
		for (i = start; i < end; i++) {
			pBeginPlan[i] = PLAN_ON;
		}
		
		pScheme = pScheme->pNext;
	}

	char *pEndPlan = pBeginPlan + PLAN_CH_NUM;
	int afterPlanNeedSize = snprintf(pEndPlan, buffSize - beforePlanNeedSize - PLAN_CH_NUM, "</Plan>\n"
								"<Scheme SchemeCycle=\"\">\n"
								"<Item Day=\"\" Time=\"\"/>\n"
								"<Item Day=\"\" Time=\"\"/>\n"
								"</Scheme>\n"
								"</Message>\n");
	return buffSize > beforePlanNeedSize + PLAN_CH_NUM + afterPlanNeedSize;
}

#define OUTPUT_PLAN_CH_NUM 144
#define OUTPUT_HOUR_MINUTE_NUM 60
#define OUTPUT_CH_MINUTE_NUM 10
#define OUTPUT_HOUR_CH_NUM (60 / 10)
Scheme *hxhtSetAlarmOutputSchemeList(char *pXmlBuff, int buffSize) {
	char *pPlan = getValueFromXmlBuff(pXmlBuff, buffSize, "Plan", NULL);
	if (pPlan != NULL) {
		Scheme *pHead = NULL;
		Scheme *pTail = NULL;
		Scheme *pScheme = NULL;
		char prevPlan = PLAN_OFF;
		char currPlan;
		int i;
		
		for (i = 0; i < OUTPUT_PLAN_CH_NUM; i++) {
			currPlan = pPlan[i];
			if (prevPlan != currPlan) {	// change
				char hour = i / OUTPUT_HOUR_CH_NUM;
				char minute = i % OUTPUT_HOUR_CH_NUM * OUTPUT_CH_MINUTE_NUM;
			
				if (currPlan == PLAN_ON) {	// new scheme, start time
					pScheme = (Scheme *) calloc(1, sizeof(Scheme));
					pScheme->startTime.hour = hour;
					pScheme->startTime.minute = minute;
					if (pHead == NULL) {	// head, first
						pHead = pScheme;
					} else {	// add to tail
						pTail->pNext = pScheme;
					}
					pTail = pScheme;
				} else if (currPlan == PLAN_OFF) {	// end time
					pScheme->endTime.hour = hour;	
					pScheme->endTime.minute = minute;
				} else {	// error
					LOGERROR("char %c in %d is error\n", currPlan, i);
					while (pHead != NULL) {
						pScheme = pHead->pNext;
						free(pHead);
						pHead = pScheme;
					}
					return NULL;
				}
			}		// END: if (prevPlan != currPlan)
			prevPlan = currPlan;
		}		// END: for (i = 0; i < OUTPUT_PLAN_CH_NUM; i++)
		return pHead;
	} else {
		LOGERROR("get Plan value error\n");
		return NULL;
	}
}

int hxhtGetAlarmOutputSchemeList(char *pXmlBuff, int buffSize, Scheme *pList) {
	int beforePlanNeedSize = snprintf(pXmlBuff, buffSize, "<Message>\n"
							"<Plan>");
	if (beforePlanNeedSize + OUTPUT_PLAN_CH_NUM >= buffSize) {
		return -1;
	}
	
	char *pBeginPlan = pXmlBuff + beforePlanNeedSize;
	memset(pBeginPlan, 0, OUTPUT_PLAN_CH_NUM);
	Scheme *pScheme = pList;
	while (pScheme != NULL) {
		int start = pScheme->startTime.hour * OUTPUT_HOUR_CH_NUM
					+ pScheme->startTime.minute / OUTPUT_CH_MINUTE_NUM;
		int end = pScheme->endTime.hour * OUTPUT_HOUR_CH_NUM
					+ pScheme->endTime.minute / OUTPUT_CH_MINUTE_NUM;
		int i;
		for (i = start; i < end; i++) {
			pBeginPlan[i] = PLAN_ON;
		}
		
		pScheme = pScheme->pNext;
	}

	char *pEndPlan = pBeginPlan + OUTPUT_PLAN_CH_NUM;
	int afterPlanNeedSize = snprintf(pEndPlan, buffSize - beforePlanNeedSize - OUTPUT_PLAN_CH_NUM, "</Plan>\n"
								"<Scheme SchemeCycle=\"\">\n"
								"<Item Day=\"\" Time=\"\"/>\n"
								"<Item Day=\"\" Time=\"\"/>\n"
								"</Scheme>\n"
								"</Message>\n");
	int needSize = beforePlanNeedSize + OUTPUT_PLAN_CH_NUM + afterPlanNeedSize;
	return needSize < buffSize ? needSize : -1;
}

#define MSG_DEF_INFO "none"
#define MSG_DEF_FROM "none"
int hxhtSendAlarmMsg(char *pXmlBuff, int buffSize, char *pDevName, int devType, int event) {
	// time
	time_t currTime;
	time(&currTime);
	struct tm *pTime = gmtime(&currTime);
	char aTime[32];
	memset(aTime, 0, sizeof(aTime));
	sprintf(aTime, "%04d-%02d-%02d %02d:%02d:%02d", pTime->tm_year + 1900,
			pTime->tm_mon, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec);

	// event name
	char aEventName[128];
	memset(aEventName, 0, sizeof(aEventName));
	sprintf(aEventName, "%s_%d_%s", aTime, devType, pDevName);

	// message
	int needSize = snprintf(pXmlBuff, buffSize, "<Message>\n"
						"<Name>%s</Name>\n"
						"<DevType>%d</DevType>\n"
						"<AlarmTime>%s</AlarmTime>\n"
						"<Type>%d</Type>\n"
						"<Info>%s</Info>\n"
						"<From>%s</From>\n"
						"</Message>\n", aEventName, devType, aTime, event, MSG_DEF_INFO, MSG_DEF_FROM);

	return needSize < buffSize ? needSize : -1;					
}

